package com.xiaoge.system.service.impl;


import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import com.xiaoge.system.entity.OssEntity;
import com.xiaoge.system.service.AliOssService;
import org.joda.time.DateTime;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Service
public class AliOssServiceImpl implements AliOssService, InitializingBean {

    private OssEntity ossEntity;

    public AliOssServiceImpl(OssEntity ossEntity) {
        this.ossEntity = ossEntity;
    }

    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;

    /*
     * 初始化后的操作，InitializingBean接口*/
    @Override
    public void afterPropertiesSet() {
        // Endpoint以杭州为例，其它Region请按实际情况填写。
        endpoint = ossEntity.getEndpoint();
        // 阿里云主账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM账号进行 API访问或日常运维，请登录RAM控制台创建RAM账号。
        accessKeyId = ossEntity.getAccessKeyId();
        accessKeySecret = ossEntity.getAccessKeySecret();
        bucketName = ossEntity.getBucketName();
    }

    /*** 创建存储空间 */
    @Override
    public void createBucket() {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

//        if (ossClient.doesBucketExist(bucketName)) {
//            throw new RuntimeException(bucketName + "在对象存储的Bucket列表中已经存在");
//        }
        // 创建存储空间。
        ossClient.createBucket(bucketName);

        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /**
     * 文件上传
     * @param file
     * @return
     * @throws IOException
     */
    @Override
    public com.xiaoge.system.entity.File upload(MultipartFile file) throws IOException {
        String uploadUrl = null;
        com.xiaoge.system.entity.File file1 = new com.xiaoge.system.entity.File();
        try {
            // 判断oss实例是否存在：如果不存在则创建，如果存在则获取 // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
            if (!ossClient.doesBucketExist(bucketName)) {
                //创建bucket
                ossClient.createBucket(bucketName);
                // 设置oss实例的访问权限：公共读
                ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
            }
            //获取上传文件流
            InputStream inputStream = file.getInputStream();
            // 构建日期路径：avatar：/2020/07/31/文件名
            String datePath = new DateTime().toString("yyyy/MM/dd");
            // 文件名：uuid.扩展名
            // 获取上传文件的全名称
            String original = file.getOriginalFilename();
            String original1 = "";
            // 去掉uuid中生成的-
            String fileName = UUID.randomUUID().toString().replaceAll("-", "");

            // 截取掉文件获得扩展名  从后截取  meizi.jpg
            // 在取位置之前，先要验证一下，字符是否存在。
            assert original != null;
            if (original.lastIndexOf(".") != -1) {
                String s = original;
                original = s.substring(s.lastIndexOf("."));
                original1 = s.substring(0, s.lastIndexOf("."));
            }

            String fileType = original;

            //拼接文件名 meizi1+"-"+uuid+.jpg/.png
            String newName = original1 + "-" + fileName + fileType;
            //生成文件夹  yyyy/MM/dd+/meizi1+"-"+uuid+.jpg/.png
            fileName = datePath + "/" + newName;

            file1.setFileName(original1 + fileType);
            file1.setSize(file.getSize());
            file1.setType(fileType);
            // 如果想要实现图片的预览效果,一定要设置一下几个点
            // 1.设置文件 ACL为反正不能为私有 要么是公共读,要么是公共读写
            // 2.一定要设置文本类型为(image/jpg)
            ObjectMetadata objectMetadata = new ObjectMetadata();
            // 设置公共读权限
            objectMetadata.setObjectAcl(CannedAccessControlList.PublicRead);
            // 设置类型
            objectMetadata.setContentType(getcontentType(fileType));
            // 文件上传至阿里云
            ossClient.putObject(bucketName, fileName, inputStream, objectMetadata);
            // 关闭OSSClient。
            ossClient.shutdown();
            // 默认十年不过期
            Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10);
            // bucket名称 文件名 过期时间
            uploadUrl = ossClient.generatePresignedUrl(bucketName, fileName, expiration).toString();
            // 获取url地址
            //uploadUrl = "https://" + bucketName + "." + endPoint + "/" + fileName;
        } catch (IOException e) {
            e.printStackTrace();
        }
        //return uploadUrl;
        assert uploadUrl != null;
        file1.setUrl(uploadUrl.substring(0, uploadUrl.indexOf("?")));
        //fileController.addFile(file1);
        return file1;
    }

    /*** 下载文件 固定路径 * @throws IOException
     * @param fileName
     * */
    @Override
    public void download(String fileName) throws IOException {
        String objectName = fileName;
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖，不存在则新建。
        OSSObject ossObject = ossClient.getObject(new GetObjectRequest(bucketName, objectName));
        // 调用ossObject.getObjectContent获取文件输入流，可读取此输入流获取其内容。
        InputStream inputStream = ossObject.getObjectContent();
        objectName = objectName.substring(objectName.lastIndexOf("/"));
        File file = new File("E:\\学习资料\\工具\\阿里OSS用户\\" + objectName);
        if (!file.exists()) {
            //先得到文件的上级目录，并创建上级目录，在创建文件
            file.getParentFile().mkdir();
            try {
                //创建文件
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        writeToLocal(file.toString(), inputStream);
        // 关闭OSSClient。
        ossClient.shutdown();
    }


    /**
     * 下载文件
     *
     * @param response
     * @param fileName
     */
    public void downLoadFile(HttpServletResponse response, String fileName) {

        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        OSSObject ossObject = ossClient.getObject(new GetObjectRequest(bucketName, fileName));

        if (ossObject != null) {
            InputStream inputStream = ossObject.getObjectContent();
            int buffer = 1024 * 10;
            byte[] data = new byte[buffer];
            try {
                int read;
                while ((read = inputStream.read(data)) != -1) {
                    response.getOutputStream().write(data, 0, read);
                }
                response.getOutputStream().flush();
                response.getOutputStream().close();
                ossObject.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /*** 列举文件 */
    @Override
    public List<com.xiaoge.system.entity.File> listFile() {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // ossClient.listObjects返回ObjectListing实例，包含此次listObject请求的返回结果。
        ObjectListing objectListing = ossClient.listObjects(bucketName);
        List<com.xiaoge.system.entity.File> files = new ArrayList<>();
        // objectListing.getObjectSummaries获取所有文件的描述信息。
        for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
            com.xiaoge.system.entity.File file = new com.xiaoge.system.entity.File();
            file.setFileName(objectSummary.getKey());
            file.setSize(objectSummary.getSize());
            System.out.println(" - " + objectSummary.getKey() + "  " +
                    "(size = " + objectSummary.getSize() + ")");
            files.add(file);
        }

        // 关闭OSSClient。
        ossClient.shutdown();
        return files;
    }

    /*** 删除文件
     * @param fileName*/
    @Override
    public void deleteFile(String fileName) {
        // <yourObjectName>表示删除OSS文件时需要指定包含文件后缀在内的完整路径，例如abc/efg/123.jpg。
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 删除文件。
        ossClient.deleteObject(bucketName, fileName);
        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /*** Description:
     * 判断OSS服务文件上传时文件的contentType *
     * * @param FilenameExtension
     * 文件后缀
     * * @return String */
    private static String getcontentType(String FilenameExtension) {
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") || FilenameExtension.equalsIgnoreCase(".jpg") || FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") || FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") || FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        if (FilenameExtension.equalsIgnoreCase(".zip")) {
            return "application/zip";
        }
        return "image/jpg";
    }

    private static void writeToLocal(String destination, InputStream input) throws IOException {
        int index;
        byte[] bytes = new byte[1024];
        FileOutputStream downloadFile = new FileOutputStream(destination);
        while ((index = input.read(bytes)) != -1) {
            downloadFile.write(bytes, 0, index);
            downloadFile.flush();
        }
        input.close();
        downloadFile.close();
    }
}